(function (angular){
  /**
   * AngularJS ellipsis 分页组件
   * @author 鸿则<hungtcs@163.com>
   */
  let PaginationModule = angular.module('pagination.module' ,[]);

  /**
   * [description]
   * @return {[type]} [description]
   */
  PaginationModule.directive('pagination' ,[function (){
    let paging = function (page ,size ,step){
      if (size < step * 2 + 6) {
        let from = 1;
        return Array.apply(null ,Array(size)).map((item ,index) => from+index);
      } else if (page < step * 2 + 1) {
        let from = 1;
        let to = step * 2 + 3;
        let array = Array.apply(null ,Array(to-from)).map((item ,index) => from+index);
        return [...array ,NaN ,size];
      } else if (page > size - step * 2) {
        let from = size - step * 2 - 1;
        let to = size + 1;
        let array = Array.apply(null ,Array(to-from)).map((item ,index) => from+index);
        return [1 ,NaN ,...array];
      } else {
        let from = page - step;
        let to = page + step + 1;
        let array = Array.apply(null ,Array(to-from)).map((item ,index) => from+index);
        return [1 ,NaN ,...array ,NaN ,size];
      }
    };
    let render = function (types ,value){
      types = types.split(' ');
      if (types.includes('PAGE_NUMBER')){
        if (types.includes('PREVIOUS')){
          return 'PREVIOUS';
        } else if (types.includes('NEXT')){
          return 'NEXT';
        } else {
          return isNaN(value) ? '...' : value;
        }
      }
    };
    let assignClasses = function (types ,value ,page ,size){
      types = types.split(' ');
      if (types.includes('PAGE_NUMBER')){
        let classes = new Array();
        if (types.includes('PREVIOUS') && page <= 1 ){
          classes.push('disable');
        } else if (types.includes('NEXT') && page >= size){
          classes.push('disable');
        } else {
          isNaN(value) && classes.push('invalid');
          value === page  && classes.push('active');
        }
        return classes;
      }
    };
    return {
      restrict: 'E' ,
      template: `
        <div class="pagination-wrapper">
          <ul class="pagination">
            <li class="page-item previous-page" ng-class="assignClasses('PAGE_NUMBER PREVIOUS' ,null ,page ,size)" >
              <a href="#!" ng-click="previous($event)" ng-bind="render('PAGE_NUMBER PREVIOUS' ,'previous')"></a>
            </li>
            <li class="page-item"
              ng-class="assignClasses('PAGE_NUMBER' ,item ,page ,size)"
              ng-repeat="item in array track by $index" >
              <a
                href="#!"
                ng-bind="render('PAGE_NUMBER' ,item)"
                ng-click="onClick($event ,item)">
              </a>
            </li>
            <li class="page-item" next-page ng-class="assignClasses('PAGE_NUMBER NEXT' ,null ,page ,size)">
              <a href="#!" ng-click="next($event)" ng-bind="render('PAGE_NUMBER NEXT' ,'next')"></a>
            </li>
          </ul>
        </div>
      ` ,
      replace: false ,
      scope: {
        size: '=' ,
        page: '=' ,
        step: '=' ,
        changed: '&' ,
        overrideRender: '&?' ,
        overrideAssignClasses: '&?'
      } ,
      link: function (scope, element, attrs ,controller ,linker){
        scope.$watch('step' ,function (newValue ,oldValue){
          scope.step = newValue < 1 ? 1 : newValue;
          scope.array = paging(scope.page ,scope.size ,scope.step);
        });
        scope.$watch('page' ,function (newValue ,oldValue){
          if (newValue >= 0 && newValue <= scope.size){
            scope.page = newValue;
            scope.array = paging(scope.page ,scope.size ,scope.step);
            scope.changed({ event: null ,page: scope.page });
          } else {
            scope.page = oldValue;
          }
        });
        scope.$watch('size' ,function (newValue ,oldValue){
          if (newValue >= 0){
            scope.size = newValue;
            if (scope.size < scope.page){ scope.page = scope.size; }
            scope.array = paging(scope.page ,scope.size ,scope.step);
          } else {
            scope.size = oldValue;
          }
        });
        scope.render = function (types ,value){
          if (scope.overrideRender){
            return scope.overrideRender({ types ,value });
          } else {
            return render(types ,value);
          }
        };
        scope.assignClasses = function (types ,value ,page ,size){
          if (scope.overrideAssignClasses){
            return scope.overrideAssignClasses({ types ,value ,page ,size });
          } else {
            return assignClasses(types ,value ,page ,size);
          }
        };
        scope.onClick = function ($event ,page){
          if (!isNaN(page) && page !== scope.page){
            scope.page = page;
            scope.array = paging(scope.page ,scope.size ,scope.step);
            scope.changed({ event: $event ,page: scope.page });
          }
        };
        scope.previous = function ($event){
          if (scope.page > 1){
            scope.page--;
            scope.array = paging(scope.page ,scope.size ,scope.step);
            scope.changed({ event: $event ,page: scope.page });
          }
        };
        scope.next = function ($event){
          if (scope.page < scope.size){
            scope.page++;
            scope.array = paging(scope.page ,scope.size ,scope.step);
            scope.changed({ event: $event ,page: scope.page });
          }
        };
      }
    };
  }]);

}(angular));
